/* $RCSFile: GenericCRMTable.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/GenericCRMTable.cs $
 * $log$
 * Revision 19 2010/10/01 11:24:59  christian.surieux
 *   Fixing temporary version on 1/10/2010
 * Revision 6 2010/08/06 19:56:32  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.Web;
using System.Web.Services.Protocols;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Data;
using System.Runtime.Serialization;

using CrmSdk;
using AddonNice.CRMWrapper;
using System.Security.Permissions;


namespace AddonNice.CRMWrapper
{

    /// <summary>
    /// Provides a DataTable that can be bound directly to a standard .NET Data Grid
    /// </summary>
    [Serializable()]
    public class GenericCrmTable<T> : DataTable where T : DynEntity
    {
        [NonSerialized()]
        public SortedList<Guid,T> dynEntitiesList     = new SortedList<Guid,T>();
        
        [NonSerialized()]
        CRMWrapperBase _wrapper = null;
        
        [NonSerialized()]
        public EntityConfig _TConfig = null;
        
        [NonSerialized()]
        string _entityName                                  = string.Empty;

        
        public CRMWrapperBase wrapper
        {
            get 
            { 
                return _wrapper; 
            }
        }

        /// <summary>
        /// Should be serialized
        /// </summary>
        public string entityName
        {
            get { return _entityName; }
            set { _entityName   =   value; } // for serializer
        }
        
        /// <summary>
        /// Get the T config to build the attributes table
        /// </summary>
        public EntityConfig TConfig
        {
            get
            {
                if (_TConfig == null)
                {
                    _TConfig = new EntityConfig(wrapper,entityName);
                    if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable<T> TConfig Ctor vflag: {0}, isAdmin: {1}, DisplayMask: [{2}] ",
                            _TConfig.entityFlags, true, _TConfig.DisplayMask),CRMQueryTraceSwitch.Sw.Info);
                }
                return _TConfig;
            }
        }

        /// <summary>
        /// In case we need to use some method after serialization, wrapper should be set
        /// </summary>
        public void SetWrapper(CRMWrapperBase w)
        { 
            _wrapper    =   w;  
        }

        public new GenericCrmTable<T> Clone()
        {
            GenericCrmTable<T> tb   =   (GenericCrmTable<T>)base.Clone();
            tb._wrapper             =   _wrapper;
            tb._entityName          =   _entityName;
            if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable<T> Clone entityname {0}", _entityName),CRMQueryTraceSwitch.Sw.Info);
            return tb;
        }

        public DataTable CloneTable()
        {
            if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable<T> CloneTable entityname {0}", _entityName),CRMQueryTraceSwitch.Sw.Info);
            return base.Clone();
        }

        
        /// <summary>
        ///  Ctor used by serializer
        /// </summary>
        protected GenericCrmTable(SerializationInfo info, StreamingContext context) : base(info,context)
        {
           if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
               Trace.WriteLine("{V]GenericCrmTable Serialization Ctor BEG.",CRMQueryTraceSwitch.Sw.Info);
        }

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info,context);
        }


        /// <summary>
        ///  Ctor used by Clone 
        /// </summary>
        protected GenericCrmTable() : base()
        {
           if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
               Trace.WriteLine("{V]GenericCrmTable protected Ctor",CRMQueryTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Normal Ctor: to use with a genericDynQueryMultiple
        /// </summary>
        public GenericCrmTable(CRMWrapperBase w,ResetWrapperHandler fn, InternalBusinessEntityCollection crmEntities,InternalQueryExpression qe) : base()
        {
            // Get the name of the entity
            _entityName                     =   w.Util.ExtractEntityName(crmEntities);
            TableName                       =   _entityName;
            _wrapper                        =   w;
            bool selCols                    =   (qe != null && qe.ColumnSet is InternalColumnSet );
            string[] colArr                 =   (selCols) ? ((InternalColumnSet)qe.ColumnSet).Attributes: null;
            if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable Ctor entityname: {0}, selCols: {1}", _entityName, selCols),CRMQueryTraceSwitch.Sw.Info);
            // Get the metadata for the currently list's entity
            // This metadata is used to create a "Property Descriptor Collection"
            PropertyDescriptorCollection _columnDescriptors     =   null;
            try
            {
                wrapper.Util.ExecForEachDynamicEntity(crmEntities,
                    delegate(InternalDynamicEntity de)
                    {
                        T ob                =   null;
                        if ( selCols )
                                ob          =   (T)Activator.CreateInstance(typeof(T), 
                                                        new object[] { w, de, _columnDescriptors,qe.ColumnSet });
                         else   ob          =   (T)Activator.CreateInstance(typeof(T), 
                                                        new object[] { w, de, _columnDescriptors,null });
                        ob.EntityMData      =   TConfig.entityMetaData;
                        if ( fn != null )
                            ob.ResetWrapperEvent    +=  fn;
                        _columnDescriptors  =   ((DynEntity)ob).PropertyDescriptorCollection;
                        // insert in cache
                        ob.ResetCache(true);
                        if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable CTor adding ob.SchemaName: [{0}], ob.PrimaryKeyGuidValue: {1}", ob.SchemaName, ob.PrimaryKeyGuidValue),CRMQueryTraceSwitch.Sw.Info);
                        dynEntitiesList.Add(ob.PrimaryKeyGuidValue,ob);
                        if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable CTor added ob.SchemaName: [{0}], type: {1}", ob.SchemaName, ob),CRMQueryTraceSwitch.Sw.Info);
                        return true; // continue
                    });
                CreateTb(colArr);
            }
            catch (SoapException sx)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable CTor sex : {0}-{1}", sx, sx.Detail.InnerText),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
            catch (CRMWrapperException wx)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable Ctor wx : {0}",wx),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
            catch (Exception ex)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable CTor ex : {0}", ex),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
        }

        /// <summary>
        /// Normal Ctor: to use with a SortedList filled with the target DynEntities
        /// </summary>
        public GenericCrmTable(CRMWrapperBase w,ResetWrapperHandler fn, string entName,SortedList<Guid,T> sList,InternalColumnSet sCol) : base()
        {
            // Get the name of the entity
            _entityName                     =   entName;
            TableName                       =   _entityName;
            _wrapper                        =   w;
            bool selCols                    =   (sCol != null && sCol is InternalColumnSet );
            string[] colArr                 =   (selCols) ? sCol.Attributes: null;
            if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable Ctor 2 entityname: {0}, selCols: {1}", _entityName, selCols),CRMQueryTraceSwitch.Sw.Info);
            try
            {
                dynEntitiesList             =   sList;
                CreateTb(colArr);
            }
            catch (SoapException sx)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable CTor 2 sex : {0}-{1}", sx, sx.Detail.InnerText),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
            catch (CRMWrapperException wx)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable Ctor 2 wx : {0}",wx),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
            catch (Exception ex)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable CTor 2 ex : {0}", ex),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
        }

        /// <summary>
        /// Generates a DataTable with all DynEntities
        /// </summary>
        public void CreateTb(string[] colArr)
        {
            if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable CreateTb BEG colArr == null: {0}, dynEntitiesList.Count: {1}",  colArr==null ,dynEntitiesList.Count),CRMQueryTraceSwitch.Sw.Info);
            // Execute the request.
            TConfig.CreateContentTable(this,colArr);
            try
            {
                for (int i = 0; i < dynEntitiesList.Count; i++)
                {
                    T s         =   dynEntitiesList.Values[i];

                    if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable CreateTb i: {0}",  i ),CRMQueryTraceSwitch.Sw.Info);
                    DataRow rw          =   NewRow();
                    wrapper.Util.ExecForEachDynamicEntityProperty(s,
                        delegate(string Name,object Val,object val2,object val3,AttributeInternalType tp)
                        {
                            if (!rw.Table.Columns.Contains(Name))
                            {
                                if ( CRMQueryTraceSwitch.Sw.TraceError )
                                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable CreateTb missing column: [{0}]", Name),CRMQueryTraceSwitch.Sw.Info);
                               return true; //continue
                            }
                            try
                            {
                                if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable CreateTb in delegate set row value Name: [{0}], Val: '{1}'", Name,Val),CRMQueryTraceSwitch.Sw.Info);
                                if ( tp == AttributeInternalType.String && Name.IndexOf("xml") > 0 )
                                        rw[Name]                    =   HttpUtility.HtmlEncode((string)Val);
                                else    rw[Name]                    =   Val;
                                if (val2 != null)
                                {
                                    switch (tp)
                                    {
                                        case AttributeInternalType.Integer:
                                        case AttributeInternalType.Decimal:
                                        case AttributeInternalType.Money:
                                        case AttributeInternalType.Float:
                                            rw[Name + CrmStr.InternalRowFormat]     =   val2;
                                            break;
                                        case AttributeInternalType.DateTime:
                                            rw[Name + CrmStr.InternalRowDate]       =   val2;
                                            break;
                                        case AttributeInternalType.Status:
                                        case AttributeInternalType.Picklist:
                                        case AttributeInternalType.Owner:
                                        case AttributeInternalType.Lookup:
                                        case AttributeInternalType.Customer:
                                            rw[Name + CrmStr.InternalRowTypecode]   =   val2;
                                            break;
                                    }
                                }
                                if (val3 != null)
                                {
                                    switch (tp)
                                    {
                                        case AttributeInternalType.DateTime:
                                            rw[Name + CrmStr.InternalRowTime]       =   val3;
                                            break;
                                        case AttributeInternalType.Owner:
                                        case AttributeInternalType.Lookup:
                                        case AttributeInternalType.Customer:
                                            rw[Name +CrmStr.InternalRowVal]         =   val3;
                                            break;
                                    }
                                }
                            }
                            catch (Exception ex1)
                            {
                                if ( CRMQueryTraceSwitch.Sw.TraceError )
                                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]EntityConfig Error mapping Name: {0}, ex : {1}", Name, ex1),CRMQueryTraceSwitch.Sw.Info);
                                throw;
                            }
                            return true; //continue
                        });

                    // Any localization necessary
                    if ( wrapper.UseFieldLocalizer && wrapper.ShouldLocalize )
                        TConfig.LocalizeColumns(s,rw,colArr,wrapper.RequestUserBaseLCID);
                    Rows.Add(rw);
                }
           }
            catch (Exception ex)
            {
                if ( CRMQueryTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]GenericCrmTable CreateTb  ex : {0}", ex),CRMQueryTraceSwitch.Sw.Info);
                throw;
            }
 
            if ( CRMQueryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]GenericCrmTable CreateTb END Count: {0}",  Rows.Count),CRMQueryTraceSwitch.Sw.Info);
        }
    }
}